package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import server.mapper.MappedContext;
import server.mapper.MappedHost;
import server.mapper.MappedWrapper;
import server.mapper.Mapper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

public class MapperUtil {
    //读取server.xml文件，获取端口、虚拟主机地址、webapps目录路径
    //读取外部web.xml文件并解析
    public static Mapper getMapper() throws DocumentException, FileNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        List<MappedWrapper> wrapperList = new ArrayList<>();
        List<MappedContext> contextList = new ArrayList<>();
        List<MappedHost> hostList = new ArrayList<>();
        MyClassLoader myClassLoader = new MyClassLoader();

        InputStream resourceAsStream = MapperUtil.class.getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();
        Element connector = (Element) rootElement.selectSingleNode("//Connector");
        //socket端口
        String port = connector.attributeValue("port");
        Element host = (Element) rootElement.selectSingleNode("//Host");
        //虚拟主机地址
        String hostname = host.attributeValue("name");
        //webapps文件夹路径
        String appBase = host.attributeValue("appBase");

        File webapps = new File(appBase);
        File[] files = webapps.listFiles();
        for (int i = 0; i < files.length; i++) {
            File webXmlFileList = getAllFile(files[i]);
            if (webXmlFileList == null){
                continue;
            }
            InputStream fileInputStream = new FileInputStream(webXmlFileList);
            document = saxReader.read(fileInputStream);
            rootElement = document.getRootElement();
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int j = 0; j < selectNodes.size(); j++) {
                Element element = selectNodes.get(j);
                // <servlet-name>lagou</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();
                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                Class<?> aClass = myClassLoader.findClass(files[i].getAbsolutePath() + "/", servletClass);
                wrapperList.add(new MappedWrapper(urlPattern, (HttpServlet) aClass.getDeclaredConstructor().newInstance()));
            }
            contextList.add(new MappedContext(files[i].getName(), wrapperList));
            wrapperList = new ArrayList<MappedWrapper>();
        }
        hostList.add(new MappedHost(hostname + ":" + port, port, appBase, contextList));
        return new Mapper(hostList);
    }

    //读取目录下web.xml文件
    private static File getAllFile(File file) {
        File[] files = file.listFiles();// 获取目录下的所有文件或文件夹
        if (files == null) {// 如果目录为空，直接退出
            return null;
        }
        // 遍历，目录下的所有文件
        for (File f : files) {
            if (f.isFile() && "web.xml".equals(f.getName())) {
                return f;
            }
        }
        return null;
    }

    // 通过url匹配到servlet
    public static HttpServlet getServlet(Request request, Mapper mapper){
        String host = request.getHost();
        String url = request.getUrl();

        List<MappedHost> hostList = mapper.getHostList();
        for (MappedHost mappedHost : hostList) {
            if (host.equals(mappedHost.getName())){
                for (MappedContext mappedContext : mappedHost.getContextList()) {
                    String contextName = mappedContext.getName();
                    for (MappedWrapper mappedWrapper : mappedContext.getWrapperList()) {
                        String wrapperName = mappedWrapper.getName();
                        if (url.equals("/" + contextName + wrapperName)){
                            return mappedWrapper.getHttpServlet();
                        }
                    }
                }
            }
        }
        return null;
    }
}
